<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vue.js 3模板插值指令示例</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <style>
      body {
        font-family: "Microsoft YaHei", Arial, sans-serif;
        max-width: 1200px;
        margin: 0 auto;
        padding: 10px;
        background-color: #f5f5f5;
      }
      .container {
        background: white;
        /* padding: 30px; */
        border-radius: 10px;
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        margin-bottom: 10px;
      }
      .example-section {
        margin-bottom: 20px;
        padding: 20px;
        border: 2px solid #e0e0e0;
        border-radius: 8px;
        background-color: #fafafa;
      }
      .example-title {
        color: #2c3e50;
        border-bottom: 2px solid #3498db;
        padding-bottom: 10px;
        margin-bottom: 20px;
      }
      .code-block {
        background-color: #2d3748;
        color: #e2e8f0;
        padding: 15px;
        border-radius: 5px;
        font-family: "Courier New", 微软雅黑;
        margin: 10px 0;
        overflow-x: auto;
      }
      .result-box {
        background-color: #e8f5e8;
        border: 1px solid #4caf50;
        padding: 15px;
        border-radius: 5px;
        margin: 10px 0;
      }
      .warning-box {
        background-color: #fff3cd;
        border: 1px solid #ffc107;
        padding: 15px;
        border-radius: 5px;
        margin: 10px 0;
      }
      .danger-box {
        background-color: #f8d7da;
        border: 1px solid #dc3545;
        padding: 15px;
        border-radius: 5px;
        margin: 10px 0;
      }
      button {
        background-color: #3498db;
        color: white;
        border: none;
        padding: 10px 20px;
        border-radius: 5px;
        cursor: pointer;
        margin: 5px;
      }
      button:hover {
        background-color: #2980b9;
      }
      input {
        padding: 8px;
        border: 1px solid #ddd;
        border-radius: 4px;
        margin: 5px;
      }
      .comparison-table {
        width: 100%;
        border-collapse: collapse;
        margin: 20px 0;
      }
      .comparison-table th,
      .comparison-table td {
        border: 1px solid #ddd;
        padding: 12px;
        text-align: left;
      }
      .comparison-table th {
        background-color: #f2f2f2;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <h1 style="text-align: center; color: #2c3e50">Vue.js 3模板插值指令实例演示</h1>
      <p style="text-align: center; color: #7f8c8d">
        本页面展示Vue.js 3模板插值指令的实际运行效果
      </p>
    </div>

    <!-- 1. 插值表达式示例 -->
    <div class="container">
      <div class="example-section">
        <h2 class="example-title">1. Vue插值表达式 {{ }}</h2>
        <h3>基本数据绑定</h3>
        <div class="code-block">
          <textarea readonly style="height: 200px; font-family: 'Consolas', 微软雅黑; font-size: 13px; padding: 0; border: none; border-radius: 0; background-color: transparent; resize: none; line-height: 1.5; box-sizing: border-box; color: #e2e8f0; width: 100%;">
<template>
  <div>
    <h2>{{ message }}</h2>
    <p>当前计数: {{ count }}</p>
    <p>计算结果: {{ count * 2 + 1 }}</p>
    <p>当前时间: {{ formatTime(new Date()) }}</p>
    <p>状态: {{ isActive ? '激活' : '未激活' }}</p>
  </div>
</template>
          </textarea>
        </div>
        <div class="result-box">
          <h3>运行效果:</h3>
          <div id="interpolation-example">
            <h2>{{ message }}</h2>
            <p>当前计数: {{ count }}</p>
            <p>计算结果: {{ count * 2 + 1 }}</p>
            <p>当前时间: {{ formatTime(new Date()) }}</p>
            <p>状态: {{ isActive ? '激活' : '未激活' }}</p>
            <button @click="count++">增加计数</button>
            <button @click="isActive = !isActive">切换状态</button>
          </div>
        </div>
      </div>
    </div>

    <!-- 2. v-text指令示例 -->
    <div class="container">
      <div class="example-section">
        <h2 class="example-title">2. v-text 指令</h2>
        <h3>对比插值表达式和v-text</h3>
        <div class="code-block">
          <textarea readonly style="height: 255px; font-family: 'Consolas', 微软雅黑; font-size: 13px; padding: 0; border: none; border-radius: 0; background-color: transparent; resize: none; line-height: 1.5; box-sizing: border-box; color: #e2e8f0; width: 100%;">
<template>
  <div>
    <!-- 使用插值表达式 -->
    <p>插值表达式: {{ textContent }}</p>
    
    <!-- 使用v-text指令 -->
    <p v-text="textContent"></p>
    
    <!-- 避免闪烁问题 -->
    <p v-text="loadingText">加载中...</p>
  </div>
</template>
          </textarea>
        </div>
        <div class="result-box">
          <h3>运行效果:</h3>
          <div id="v-text-example">
            <p>插值表达式: {{ textContent }}</p>
            <p v-text="textContent"></p>
            <p v-text="loadingText">加载中...</p>
            <button @click="updateText">更新文本</button>
          </div>
        </div>
        <div class="warning-box">
          <strong>注意:</strong>
          v-text会完全替换元素的文本内容，而插值表达式可以与其他文本混合使用。
        </div>
      </div>
    </div>

    <!-- 3. v-html指令示例 -->
    <div class="container">
      <div class="example-section">
        <h2 class="example-title">3. v-html 指令</h2>
        <h3>HTML内容渲染</h3>
        <div class="code-block">
          <textarea readonly style="height: 220px; font-family: 'Consolas', 微软雅黑; font-size: 13px; padding: 0; border: none; border-radius: 0; background-color: transparent; resize: none; line-height: 1.5; box-sizing: border-box; color: #e2e8f0; width: 100%;">
<template>
  <div>
    <!-- 普通文本绑定 -->
    <p>普通绑定: {{ htmlContent }}</p>
    <!-- HTML内容绑定 -->
    <div v-html="htmlContent"></div>
    <!-- 富文本内容 -->
    <div v-html="richTextContent"></div>
  </div>
</template>
          </textarea>
        </div>
        <div class="result-box">
          <h3>运行效果:</h3>
          <div id="v-html-example">
            <p>普通绑定: {{ htmlContent }}</p>
            <div v-html="htmlContent"></div>
            <hr />
            <h4>富文本内容:</h4>
            <div v-html="richTextContent"></div>
            <button @click="updateHtmlContent">更新HTML内容</button>
          </div>
        </div>
        <div class="danger-box">
          <strong>⚠️ 安全警告:</strong>
          v-html存在XSS攻击风险！永远不要对用户输入使用v-html指令。 <br /><br />
          <strong>危险示例:</strong>
          <div
            class="code-block"
            style="background-color: #721c24; color: #f8d7da"
          >
            // 危险！用户输入可能包含恶意脚本 userInput:
            '&lt;script&gt;alert("XSS攻击")&lt;/script&gt;' &lt;div
            v-html="userInput"&gt;&lt;/div&gt;
          </div>
        </div>
      </div>
    </div>

    <!-- 4. v-once指令示例 -->
    <div class="container">
      <div class="example-section">
        <h2 class="example-title">4. v-once 指令</h2>
        <h3>一次性绑定演示</h3>
        <div class="code-block">
          <textarea readonly style="height: 300px; font-family: 'Consolas', 微软雅黑; font-size: 13px; padding: 0; border: none; border-radius: 0; background-color: transparent; resize: none; line-height: 1.5; box-sizing: border-box; color: #e2e8f0; width: 100%;">
<template>
  <div>
    <!-- 普通绑定：会随数据变化 -->
    <p>普通绑定: {{ onceCounter }}</p>
    <!-- 一次性绑定：不会变化 -->
    <p v-once>一次性绑定: {{ onceCounter }}</p>
    <!-- 昂贵计算的一次性绑定 -->
    <div v-once>
      <h4>用户信息 (只渲染一次):</h4>
      <p>用户名: {{ user.name }}</p>
      <p>注册时间: {{ user.registerDate }}</p>
    </div>
  </div>
</template>
          </textarea>
        </div>
        <div class="result-box">
          <h3>运行效果:</h3>
          <div id="v-once-example">
            <p>普通绑定: {{ onceCounter }}</p>
            <p v-once>一次性绑定: {{ onceCounter }}</p>
            <div v-once>
              <h4>用户信息 (只渲染一次):</h4>
              <p>用户名: {{ user.name }}</p>
              <p>注册时间: {{ user.registerDate }}</p>
            </div>
            <button @click="onceCounter++">增加计数器</button>
            <button @click="updateUser">更新用户信息</button>
            <p>
              <small>注意观察：普通绑定会更新，v-once绑定的内容不会改变</small>
            </p>
          </div>
        </div>
      </div>
    </div>

    <!-- 5. 综合对比示例 -->
    <div class="container">
      <div class="example-section">
        <h2 class="example-title">5. 指令对比总结</h2>
        <table class="comparison-table">
          <thead>
            <tr>
              <th>指令</th>
              <th>用途</th>
              <th>HTML转义</th>
              <th>性能</th>
              <th>安全性</th>
              <th>使用场景</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td><code>{{ }}</code></td>
              <td>文本插值</td>
              <td>✅ 是</td>
              <td>普通</td>
              <td>安全</td>
              <td>大部分文本显示</td>
            </tr>
            <tr>
              <td><code>v-text</code></td>
              <td>文本内容</td>
              <td>✅ 是</td>
              <td>普通</td>
              <td>安全</td>
              <td>避免闪烁、完全替换</td>
            </tr>
            <tr>
              <td><code>v-html</code></td>
              <td>HTML内容</td>
              <td>❌ 否</td>
              <td>普通</td>
              <td>⚠️ 风险</td>
              <td>富文本、可信HTML</td>
            </tr>
            <tr>
              <td><code>v-once</code></td>
              <td>一次性绑定</td>
              <td>取决于配合指令</td>
              <td>⚡ 高</td>
              <td>取决于内容</td>
              <td>静态内容、性能优化</td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>

    <!-- 6. 实践练习 -->
    <div class="container">
      <div class="example-section">
        <h2 class="example-title">6. 实践练习</h2>
        <h3>用户信息展示卡片</h3>
        <div id="practice-example">
          <div
            style="
              border: 1px solid #ddd;
              padding: 20px;
              border-radius: 8px;
              background: #f9f9f9;
            "
          >
            <h3 v-once>{{ practiceUser.name }} 的个人信息</h3>
            <p>
              <strong>邮箱:</strong> <span v-text="practiceUser.email"></span>
            </p>
            <p><strong>个人简介:</strong></p>
            <div
              v-html="practiceUser.bio"
              style="background: white; padding: 10px; border-radius: 4px"
            ></div>
            <p><strong>访问次数:</strong> {{ visitCount }}</p>
            <p>
              <strong>注册时间:</strong>
              <span v-once>{{ practiceUser.registerDate }}</span>
            </p>
            <button @click="visitCount++">模拟访问</button>
          </div>
        </div>
      </div>
    </div>

    <script>
      const { createApp, ref, reactive } = Vue;

      // 插值表达式示例
      createApp({
        setup() {
          const message = ref("Hello Vue 插值表达式！");
          const count = ref(0);
          const isActive = ref(true);

          const formatTime = (date) => {
            return date.toLocaleTimeString();
          };

          return {
            message,
            count,
            isActive,
            formatTime
          };
        },
      }).mount("#interpolation-example");

      // v-text示例
      createApp({
        setup() {
          const textContent = ref("这是通过v-text显示的内容");
          const loadingText = ref("数据加载完成！");

          const updateText = () => {
            textContent.value = "文本已更新 - " + new Date().toLocaleTimeString();
            loadingText.value = "新的加载状态 - " + Math.random().toFixed(2);
          };

          return {
            textContent,
            loadingText,
            updateText
          };
        },
      }).mount("#v-text-example");

      // v-html示例
      createApp({
        setup() {
          const htmlContent = ref("<strong>这是粗体文本</strong>");
          const richTextContent = ref(`
                <div style="background: linear-gradient(45deg, #ff6b6b, #4ecdc4); padding: 15px; border-radius: 8px; color: white;">
                    <h3>🎉 富文本内容示例</h3>
                    <p>这里包含了 <em>斜体</em>、<strong>粗体</strong> 和 <u>下划线</u> 文本。</p>
                    <ul>
                        <li>列表项 1</li>
                        <li>列表项 2</li>
                    </ul>
                </div>
            `);

          const updateHtmlContent = () => {
            const colors = [
              "#ff6b6b",
              "#4ecdc4",
              "#45b7d1",
              "#96ceb4",
              "#feca57",
            ];
            const randomColor = colors[Math.floor(Math.random() * colors.length)];
            htmlContent.value = `<span style="color: ${randomColor}; font-weight: bold; font-size: 18px;">🌈 颜色已更新！</span>`;
          };

          return {
            htmlContent,
            richTextContent,
            updateHtmlContent
          };
        },
      }).mount("#v-html-example");

      // v-once示例
      createApp({
        setup() {
          const onceCounter = ref(0);
          const user = reactive({
            name: "张三",
            registerDate: "2023-01-15",
          });

          const updateUser = () => {
            // 注意：v-once绑定的内容不会更新
            user.name = "李四_" + Math.random().toFixed(2);
            user.registerDate = new Date().toLocaleDateString();
          };

          return {
            onceCounter,
            user,
            updateUser
          };
        },
      }).mount("#v-once-example");

      // 实践练习示例
      createApp({
        setup() {
          const practiceUser = reactive({
            name: "王小明",
            email: "wangxiaoming@example.com",
            bio: `
                    <p>我是一名<strong>全栈开发工程师</strong>，专注于:</p>
                    <ul>
                        <li>🚀 <em>Vue.js</em> 前端开发</li>
                        <li>⚡ <em>Node.js</em> 后端开发</li>
                        <li>📱 移动端应用开发</li>
                    </ul>
                    <p style="color: #666; font-style: italic;">"代码改变世界，创新驱动未来！"</p>
                `,
            registerDate: "2022-03-15",
          });
          const visitCount = ref(1);

          return {
            practiceUser,
            visitCount
          };
        },
      }).mount("#practice-example");
    </script>
  </body>
</html>
